package org.zy.server;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleStateEvent;
import org.zy.core.Message;

public class ClientHandler extends SimpleChannelInboundHandler<Message> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
        // 代理服务器读取客户端数据
        byte type = msg.getType();
        switch (type) {
            case Message.TYPE_HEARTBEAT:
                Message heartMsg = new Message(Message.TYPE_HEARTBEAT);
                ctx.channel().writeAndFlush(heartMsg);
                break;

            case Message.TYPE_CONNECT:
                // 客户端与代理服务器连接
                String connectVisitorId = new String(msg.getData());
                if (null == connectVisitorId || connectVisitorId.length() == 0 || "client".equals(connectVisitorId)) {
                    // 代理服务器与客户端主交互通道
                    System.out.println("客户端与代理服务器连接成功");
                    ChannelManager.CLIENT_MAIN_CHANNEL = ctx.channel();
                } else {
                    // 绑定访客与客户端连接
                    System.out.println("客户端与访客绑定成功");
                    Channel visitorChannel = ChannelManager.VISITOR_CHANNEL_MAP.get(connectVisitorId);
                    if (null != visitorChannel) {
                        ctx.channel().attr(ChannelManager.VISITOR_ID).set(connectVisitorId);
                        ChannelManager.CLIENT_CHANNEL_MAP.put(connectVisitorId, ctx.channel());

                        visitorChannel.config().setOption(ChannelOption.AUTO_READ, true);
                    }
                }
                break;

            case Message.TYPE_DISCONNECT:
                // 客户端断开连接
                System.out.println("客户端断开连接");

                String disConnectVisitorId = new String(msg.getData());
                ChannelManager.removeVisitorAndClose(disConnectVisitorId);
                break;

            case Message.TYPE_TRANSFER:
                // 客户端数据发送到访客
                System.out.println("客户端数据发送到访客");

                ByteBuf buf = ctx.alloc().buffer(msg.getData().length);
                buf.writeBytes(msg.getData());

                String transferVisitorId = ctx.channel().attr(ChannelManager.VISITOR_ID).get();
                Channel visitorChannel = ChannelManager.VISITOR_CHANNEL_MAP.get(transferVisitorId);
                if (null != visitorChannel) {
                    visitorChannel.writeAndFlush(buf);
                }
                break;

            default:
                // 数据错误
        }
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        String visitorId = ctx.channel().attr(ChannelManager.VISITOR_ID).get();
        if (null == visitorId || visitorId.length() == 0) {
            super.channelWritabilityChanged(ctx);
            return;
        }

        Channel visitorChannel = ChannelManager.VISITOR_CHANNEL_MAP.get(visitorId);
        if (null != visitorChannel) {
            visitorChannel.config().setOption(ChannelOption.AUTO_READ, ctx.channel().isWritable());
        }

        super.channelWritabilityChanged(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String visitorId = ctx.channel().attr(ChannelManager.VISITOR_ID).get();
        if (null == visitorId || visitorId.length() == 0) {
            super.channelInactive(ctx);
            return;
        }

        Channel visitorChannel = ChannelManager.VISITOR_CHANNEL_MAP.get(visitorId);
        if (null != visitorChannel && visitorChannel.isActive()) {
            // 数据发送完成后关闭
            visitorChannel.writeAndFlush(Unpooled.EMPTY_BUFFER)
                    .addListener(ChannelFutureListener.CLOSE);
            visitorChannel.close();
        } else {
            ctx.channel().close();
        }

        ChannelManager.removeVisitor(visitorId);

        super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            switch (event.state()) {
                case READER_IDLE:
                    ctx.channel().close();
                    break;
                case WRITER_IDLE:
                    break;
                case ALL_IDLE:
                    break;
            }
        }
    }
}